//SPDX-FileCopyrightText: Copyright 2022-2024 深圳市同心圆网络有限公司
//SPDX-License-Identifier: GPL-3.0-only

use git2::{Commit, Error, Repository};
use serde::Serialize;
use std::collections::HashMap;
use std::path::PathBuf;

#[derive(Serialize, Clone, Debug)]
struct CommitInfo {
    id: String,
    summary: String,
    time_stamp: i64,
    commiter: String,
    email: String,
}

fn list_commit(commit_map: &mut HashMap<String, CommitInfo>, commit: &Commit) -> Result<(), Error> {
    let commit_id = commit.id().to_string();
    if commit_map.contains_key(&commit_id) {
        return Ok(());
    }

    commit_map.insert(
        commit_id.clone(),
        CommitInfo {
            id: commit_id.clone(),
            summary: String::from(commit.summary().unwrap_or_default()),
            time_stamp: commit.time().seconds() * 1000,
            commiter: String::from(commit.committer().name().unwrap_or_default()),
            email: String::from(commit.committer().email().unwrap_or_default()),
        },
    );
    let count = commit.parent_count();
    if count == 0 {
        return Ok(());
    }
    for index in 0..count {
        let parent_commit = commit.parent(index);
        if parent_commit.is_err() {
            return Err(parent_commit.err().unwrap());
        }
        let parent_commit = parent_commit.unwrap();
        let result = list_commit(commit_map, &parent_commit);
        if result.is_err() {
            return result;
        }
    }
    return Ok(());
}

pub fn exec(git_path: PathBuf, ref_name: &String) -> Result<(), Error> {
    let repo = Repository::open(git_path);
    if repo.is_err() {
        return Err(repo.err().unwrap());
    }
    let repo = repo.unwrap();

    let ref_obj = repo.find_reference(ref_name);
    if ref_obj.is_err() {
        return Err(ref_obj.err().unwrap());
    }
    let ref_obj = ref_obj.unwrap();

    let commit = ref_obj.peel_to_commit();
    if commit.is_err() {
        return Err(commit.err().unwrap());
    }
    let commit = commit.unwrap();
    let mut commit_map: HashMap<String, CommitInfo> = HashMap::new();
    let result = list_commit(&mut commit_map, &commit);
    if result.is_err() {
        return Err(result.err().unwrap());
    }

    let mut commit_list: Vec<CommitInfo> = commit_map.into_values().collect();
    commit_list.sort_by(|a, b| b.time_stamp.cmp(&a.time_stamp));
    println!("{}", serde_json::to_string(&commit_list).unwrap());
    return Ok(());
}
